package chemistry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;

public class Reactor {
	private ElementList elements;
	private int[] activitySeries;
	private int[] honclbrif;
	
	public Reactor(ElementList elements){
		this.elements = elements;
		this.activitySeries = genActivitySeries();
		this.honclbrif = genHonclbrif();
	}
	
	//Activity series of metals, metals with higher indices will be replaced by metals of lower indices
	public int[] genActivitySeries(){
		int[] nums = {19, 11, 3, 38, 20, 12, 13, 30, 24, 26, 48, 27, 28, 50, 82, 1, 29, 47, 80, 79, 78};
		return nums;
	}
	
	//Diatomic elements
	public int[] genHonclbrif(){
		int[] nums = {1, 7, 8, 9, 17, 35, 53};
		return nums;
	}
	
	//Checks if a metal is more active than another
	public boolean active(Element a, Element b){
		int aInd = 22;
		int bInd = 22;
		int aNum = a.getNumber();
		int bNum = b.getNumber();
		for (int i = 0; i < 21; i++){
			int val = this.activitySeries[i];
			if (aNum == val){
				aInd = i;
			}
			if (bNum == val){
				bInd = i;
			}
		}
		return aInd < bInd;
	}
	
	//Reaction, double replacement disabled until solutions work
	/**
	 * @param a
	 * @param b
	 * @return
	 */
	public ArrayList<String> react(ArrayList<Element> a, ArrayList<Element> b){
		TreeSet<Element> setA = new TreeSet<Element>(a);
		TreeSet<Element> setB = new TreeSet<Element>(b);
		ArrayList<String> end;
		//If each reactant is a single element and a and b aren't the same (to catch diatoms)
		if (setA.size() == 1 && setB.size() == 1){
			if ((a.get(0) == b.get(0)) && (a.size() > 1 || b.size() > 1)){
				end = null; //reaction results in diatomic compound
			} else {
				end = synthesis(a.get(0), b.get(0));
			}
		} else {
			ArrayList<Element> na = new ArrayList<Element>();
			ArrayList<Element> nb = new ArrayList<Element>();
			for (Element e:setA){
				na.add(e);
			}
			for (Element e:setB){
				nb.add(e);
			}
			//To prevent diatoms from eating everything
			if (setA.size() == 1 && setB.size() == 1){
				end = null;
//			  } else if (setA.size() == 2 && setB.size() == 2){
//				  end = doubleReplacement(na, nb);
			} else {
				end = replacement(na, nb);
			}
		}
		//Other reaction methods return null if no reaction takes place
//		if (end == null){
//			end = new ArrayList<String>();
//			end.add(FormulaParser.deparse(a));
//			end.add(FormulaParser.deparse(b));
//		}
		return end;
	}
	
	public ArrayList<String> synthesis(Element a, Element b){
		ArrayList<String> end = new ArrayList<String>();
		/*Checks if the elements are diatomic or different, if they have different charges, and if at least one
		is a nonmetal*/
		if ((Arrays.binarySearch(this.honclbrif, a.getNumber()) >= 0) ||
				((a != b) &&  a.getCharge() != 0 && b.getCharge() != 0 && (elements.isNonMetal(a)
						|| elements.isNonMetal(b)))){
			ArrayList<Element> product = new ArrayList<Element>();
			//for (int i=0; i < Math.abs(a.getCharge()); i++){
				product.add(b);
			//}
			//for (int i=0; i < Math.abs(b.getCharge()); i++){
				product.add(a);
			//}
			end.add(FormulaParser.deparse(product, elements));
			return end;
		}
		return null;
	}
	
	//Switches elements in two compounds
	public ArrayList<String> doubleReplacement(ArrayList<Element> a, ArrayList<Element> b){
		int am = 0;
		int bm = 0;
		if (elements.isNonMetal(a.get(1))){
			am = 1;
		}
		if (elements.isNonMetal(b.get(1))){
			bm = 1;
		}
		int an = 1 - am;
		int bn = 1 - bm;
		try{
			ArrayList<String> end = synthesis(a.get(am), b.get(bn));
			for (String s: synthesis(a.get(an), b.get(bm))){
				end.add(s);
			}
			return end;
		} catch (NullPointerException e) {
			return null;
		}
	}
	
	//Runs several levels of if else statements based on type of double replacement and positioning inside the array
	public ArrayList<String> replacement(ArrayList<Element> a, ArrayList<Element> b){
		try {
			if (a.get(0).getCharge() == 0 || b.get(0).getCharge() == 0){
				return null;
			}
			ArrayList<String> end = new ArrayList<String>();
			//Checks whether a or b is the compound
			if (a.size() >= 2){
				//Checks for the same element occurring twice
				if (a.get(0).equals(b.get(0)) || a.get(1).equals(b.get(0))){
					return null;
				}
				//Checks if the single element is a metal
				if (elements.isNonMetal(b.get(0))){
					//Checks which element in the compound mathches the single element (metal-metal, nonmetal-nonmetal)
					if (elements.isNonMetal(a.get(0))){
						//Synthesizes and returns new single element and the compound
						end = synthesis(a.get(1), b.get(0));
						end.add(a.get(0).getSymbol());
					} else {
						end = synthesis(a.get(0), b.get(0));
						end.add(a.get(1).getSymbol());
					}
				} else {
					if (!elements.isNonMetal(a.get(0))){
						//Checks activity series
						if (active(a.get(0), b.get(0))){
						    	return null;
						}
						end = synthesis(a.get(1), b.get(0));
						end.add(a.get(0).getSymbol());
					} else {
						if ((active(a.get(1), b.get(0)))){
					    	return null;
						}
						end = synthesis(a.get(0), b.get(0));
						end.add(a.get(1).getSymbol());
					}
				}
			} else {
				if (a.get(0).equals(b.get(0)) || a.get(0).equals(b.get(1))){
					return null;
				}
				if (elements.isNonMetal(a.get(0))){
					if (elements.isNonMetal(b.get(0))){
						end = synthesis(b.get(1), a.get(0));
						end.add(b.get(0).getSymbol());
					} else {
						end = synthesis(b.get(0), a.get(0));
						end.add(b.get(1).getSymbol());
					}
				} else {
					if (!elements.isNonMetal(b.get(0))){
						if (active(a.get(0), b.get(0))){
					    	return null;
						}
						end = synthesis(b.get(1), a.get(0));
						end.add(b.get(0).getSymbol());
					} else {
						if (active(a.get(0), b.get(1))){
					    	return null;
						}
						end = synthesis(b.get(0), a.get(0));
						end.add(b.get(1).getSymbol());
					}
				}
			}
			return end;
		} catch (NullPointerException e) {
			return null;
		}
	}
}
